

#include "../Functions/cube_functions.h"
#include "../Functions/binary.h"
#include "animations.h"
#include "shapes.h"
#include "stdlib.h"
#include "../Functions/rotation.h"
#include "../Functions/translation.h"
#include "../Functions/ab.h"

#include "math.h"

#include "arm_math.h"
#include "math_helper.h"

extern void cube_show_loop(unsigned long cycles);

#define MONSTER_RIGHT invaders_move_right((*m_layer), m_pos);
#define MONSTER_LEFT invaders_move_left((*m_layer), m_pos);
#define MONSTER_DOWN  invaders_move_down(m_layer, (*m_pos));
#define INV_DELAY invader_show_loop(&shot_layer, &shot_pos, &monster_layer, &monster_pos);
#define DEF_RIGHT move_x_fwd( 0, 0, 7, 1); defender_pos += 0x10;
#define DEF_LEFT move_x_rev( 0, 0, 7, 1); defender_pos -= 0x10;
#define DEF_BACK move_z_fwd( 0, 0, 1, 7); defender_pos += 0x01;
#define DEF_FWD move_z_rev( 0, 0, 1, 7); defender_pos -= 0x01;
#define DEF_FIRE def_fire( &shot_layer, &shot_pos, defender_pos );




double map(double in, double inMin, double inMax, double outMin, double outMax);


void cube_stripes( )
{
        int i,j,p,times = 1;


        for (p = 0;p<times;p++ ){
            clear();
        for ( i = 0; i < 8; i++) {
                cube[0][0] |= ( 1 << i );
                cube[1][7] |= ( 1 << (7-i) );
                cube[2][0] |= ( 1 << i );
                cube[3][7] |= ( 1 << (7-i) );
                cube[4][0] |= ( 1 << i );
                cube[5][7] |= ( 1 << (7-i) );
                cube[6][0] |= ( 1 << i );
                cube[7][7] |= ( 1 << (7-i) );
                cube_show_loop(10);
        }
        for (j = 1; j < 8; j++) {
                clear();
                for (i = 0; i < 8; i++) {
                        cube[0][j] |= ( 1 << i );
                        cube[1][7-j] |= ( 1 << i );
                        cube[2][j] |= ( 1 << i );
                        cube[3][7-j] |= ( 1 << i );
                        cube[4][j] |= ( 1 << i );
                        cube[5][7-j] |= ( 1 << i );
                        cube[6][j] |= ( 1 << i );
                        cube[7][7-j] |= ( 1 << i );
                }
                cube_show_loop(10);

        	}
        }
}


void animation1(unsigned long numLoops)
{
    int x;

        while(numLoops)
        {
                for(x=0; x<NUM_LAYERS; x++)
                {
                clear();
                        cube[x][0]= B8(11111111);
                        cube[x][1]= B8(11111111);
                        cube[x][2]= B8(11111111);
                        cube[x][3]= B8(11111111);
                        cube[x][4]= B8(11111111);
                        cube[x][5]= B8(11111111);
                        cube[x][6]= B8(11111111);
                        cube[x][7]= B8(11111111);


                        cube_show_loop(10);
                }
                for(x=NUM_LAYERS; x>0; x--)
                {
                clear();

                        cube[x-1][0]= B8(11111111);
                        cube[x-1][1]= B8(11111111);
                        cube[x-1][2]= B8(11111111);
                        cube[x-1][3]= B8(11111111);
                        cube[x-1][4]= B8(11111111);
                        cube[x-1][5]= B8(11111111);
                        cube[x-1][6]= B8(11111111);
                        cube[x-1][7]= B8(11111111);

                        cube_show_loop(5);
                }

                numLoops--;

        }

}

void animation2(unsigned long numLoops)
{
    int x=5;
    int y,z;
    int loops = numLoops;
    unsigned long data = 0x01;

    while(loops!=0)
    {
        for(y=0; y<NUM_LAYERS; y++)
        {

                for(z=0; z<NUM_ICS; z++)
                {
                        cube[y][z]=data;
                }

                cube_show_loop(x);
        }
        x+=5;

        if(data==0x8000)
        {
                data=0x01;
        }

                data = data<<1;

        loops--;

    }
}

void cube_belt_wipe( void )
{
        int i,layer;
        clear();
        for (layer = 8; layer != 0; layer--){
                cube[layer-1][0] |= 0xFF;
                cube[layer-1][7] |= 0xFF;
                for ( i = 1; i < 7; i++){ cube[layer-1][i] |= B8(10000001); }
                cube_show_loop(10);
        }
        for (layer = 8; layer != 0; layer--){
                for ( i = 0; i < 8; i++){ cube[layer-1][i] = 0x00; }
                cube_show_loop(10);
        }
}

/* freaky: when looking at this for a while in a dark room
 * you begin to see pink dots in the cube */
void cube_stars( void )
{

        int j, i, loops, randx, randy, randz;
        clear();
        for ( j = 1; j < 10; j++){
                for ( loops = 0; loops < 18; loops++){
                        clear();
                        for ( i = 0; i< j; i++){
                                 randx = (int)rand()%8;
                                 randy = (int)rand()%8;
                                 randz = (int)rand()%8;
                                cube[randy][randx] = (1 << randz);
                        }
//              cube[randy][randx] &= ~(1 << randz);
                        cube_show_loop(10);
                }
        }
}

/* explosion illuminate all starting at middle an turn off in same order */
void cube_explosion( void )
{
        int i,j,k;
        int led_state = B8(00011000);
        for ( i = 0; i <= 4; i++){
                for ( j = 3; j <= (i+3); j++) {
                        for ( k = 3; k <= (i+3); k++){
                                cube[j][7-k] = led_state;
                                cube[j][k] = led_state;
                                cube[7-j][7-k] = led_state;
                                cube[7-j][k] = led_state;
                        }
                }
                cube_show_loop(4*(2*i+1));
                led_state |= (1 << (3-i)) | (1 << (4+i));
        }
        cube_show_loop(8);
        for ( i = 0; i <= 4; i++){
                led_state &= ~((1 << (3-i)) | (1 << (4+i)));
                for ( j = 3; j <= (i+3); j++) {
                        for (k = 3; k <= (i+3); k++){
                                cube[j][7-k] = led_state;
                                cube[j][k] = led_state;
                                cube[7-j][7-k] = led_state;
                                cube[7-j][k] = led_state;
                        }
                }
                cube_show_loop(4*(2*i+1));
        }
        cube_show_loop(8);
}

/* shrinking outline */
void outline_shrink( void )
{
        int i;
        clear();
        for ( i = 1; i < 7; i++ ){
                cube[i][0] = B8(10000001);
                cube[i][7] = B8(10000001);
        }
        for ( i = 1; i < 7; i++){
                cube[0][i] = B8(10000001);
                cube[7][i] = B8(10000001);
        }
        cube[0][0] = 0xFF;
        cube[7][0] = 0xFF;
        cube[0][7] = 0xFF;
        cube[7][7] = 0xFF;
        cube_show_loop(1);
        clear();

        for ( i = 2; i < 6; i++ ){
                cube[i][1] = B8(01000010);
                cube[i][6] = B8(01000010);
        }
        for ( i = 2; i < 6; i++){
                cube[1][i] = B8(01000010);
                cube[6][i] = B8(01000010);
        }
        cube[1][1] = B8(01111110);
        cube[6][1] = B8(01111110);
        cube[1][6] = B8(01111110);
        cube[6][6] = B8(01111110);
        cube_show_loop(2);
        clear();

        for ( i = 3; i < 5; i++ ){
                cube[i][2] = B8(00100100);
                cube[i][5] = B8(00100100);
        }
        for ( i = 3; i < 5; i++){
                cube[2][i] = B8(00100100);
                cube[5][i] = B8(00100100);
        }
        cube[2][2] = B8(00111100);
        cube[5][2] = B8(00111100);
        cube[2][5] = B8(00111100);
        cube[5][5] = B8(00111100);
        cube_show_loop(3);
        clear();

        cube[3][3] = B8(00011000);
        cube[4][3] = B8(00011000);
        cube[3][4] = B8(00011000);
        cube[4][4] = B8(00011000);
        cube_show_loop(4);
}

void cubes_2( void )
{
        int i;

        clear();

        for ( i = 0; i < 8; i++ ){
                cube[0][i] = 0xFF;
                cube[1][i] = 0xFF;
        }
        cube_show_loop(10);
        for ( i = 0; i < 6; i++) {
                move_y_fwd(2,2,3,3);
                move_y_fwd(2,6,3,7);
                move_y_fwd(6,2,7,3);
                move_y_fwd(6,6,7,7);
                cube_show_loop(CUBE2);
        }
        for ( i = 0; i < 4; i++) {
                move_y_fwd(0,0,1,1);
                move_y_fwd(0,4,1,5);
                move_y_fwd(4,0,5,1);
                move_y_fwd(4,4,5,5);
                cube_show_loop(CUBE2);
        }
        for ( i = 0; i < 2; i++) {
                move_y_fwd(2,0,3,1);
                move_y_fwd(6,0,7,1);
                move_y_fwd(2,4,3,5);
                move_y_fwd(6,4,7,5);
                cube_show_loop(CUBE2);
        }

        for ( i = 0; i < 4; i++) {
                move_y_rev(6,2,7,3);
                cube_show_loop(CUBE2);
        }
        for ( i = 0; i < 2; i++) {
                move_y_rev(4,0,5,1);
                cube_show_loop(CUBE2);
        }
        for ( i = 0; i < 6; i++) {
                move_z_fwd(2,4,3,5);
                cube_show_loop(CUBE2);
        }

        for ( i = 0; i < 2; i++) {
                move_y_rev(2,0,3,1);
                cube_show_loop(CUBE2);
        }

        for ( i = 0; i < 6; i++) {
                move_z_fwd(0,2,1,3);
                cube_show_loop(CUBE2);
        }

        for ( i = 0; i < 4; i++) {
                move_y_fwd(0,2,1,3);
                cube_show_loop(CUBE2);
        }

        for ( i = 0; i < 2; i++) {
                move_x_fwd(2,4,3,5);
                cube_show_loop(CUBE2);
        }
        cube_show_loop(CUBE2);
}


/* cubemoving 4x4 */
void cubes_4( void )
{
        int layer, fourtimes;
        clear();
        for ( layer = 0; layer <= 3; layer++){
                cube[layer][0] = B8(00001111);
                cube[layer][1] = B8(00001111);
                cube[layer][2] = B8(00001111);
                cube[layer][3] = B8(00001111);
        }
        for ( layer = 4; layer <= 7; layer++){
                cube[layer][4] = B8(11111111);
                cube[layer][5] = B8(11111111);
                cube[layer][6] = B8(11111111);
                cube[layer][7] = B8(11111111);
        }
        cube_show_loop(CUBE4);

        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_y_rev(4,0,7,3);
                cube_show_loop(CUBE4);

        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_z_fwd(0,0,3,3);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_y_fwd(0,4,3,7);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_y_rev(4,4,7,7);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_x_rev(0,0,3,3);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_z_rev(4,0,7,3);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_z_fwd(4,0,7,3);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_y_fwd(4,4,7,7);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_x_fwd(0,0,3,3);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_y_fwd(4,0,7,3);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_y_rev(0,4,3,7);
                cube_show_loop(CUBE4);
        }
        for ( fourtimes = 0; fourtimes <= 3; fourtimes++){
                move_z_rev(0,0,3,3);
                cube_show_loop(CUBE4);
        }
}

/* another wave simulation */
void cube_sonic( void )
{
        int i, deg, layer, mode, sonic_layers;

        for( i = 0; i < 10; i++){
                clear();
                cube_show_loop(20);
                 mode = rand()%5;
                 sonic_layers = (rand()%8)+1;
                if (mode <= 3){
                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(10000000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(01000000);
                                cube[layer][1] = B8(10000000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(00100000);
                                cube[layer][1] = B8(00100000);
                                cube[layer][2] = B8(11000000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(00010000);
                                cube[layer][1] = B8(00010000);
                                cube[layer][2] = B8(00100000);
                                cube[layer][3] = B8(11000000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(00001000);
                                cube[layer][1] = B8(00001000);
                                cube[layer][2] = B8(00010000);
                                cube[layer][3] = B8(00110000);
                                cube[layer][4] = B8(11000000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(00000100);
                                cube[layer][1] = B8(00000100);
                                cube[layer][2] = B8(00000100);
                                cube[layer][3] = B8(00001000);
                                cube[layer][4] = B8(00010000);
                                cube[layer][5] = B8(11100000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(00000010);
                                cube[layer][1] = B8(00000010);
                                cube[layer][2] = B8(00000010);
                                cube[layer][3] = B8(00000100);
                                cube[layer][4] = B8(00001000);
                                cube[layer][5] = B8(00010000);
                                cube[layer][6] = B8(11100000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(00000001);
                                cube[layer][1] = B8(00000001);
                                cube[layer][2] = B8(00000001);
                                cube[layer][3] = B8(00000010);
                                cube[layer][4] = B8(00000010);
                                cube[layer][5] = B8(00000100);
                                cube[layer][6] = B8(00011000);
                                cube[layer][7] = B8(11100000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][4] = B8(00000001);
                                cube[layer][5] = B8(00000010);
                                cube[layer][6] = B8(00000100);
                                cube[layer][7] = B8(00001000);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][6] = B8(00000001);
                                cube[layer][7] = B8(00000010);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);

                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][7] = B8(00000001);
                        }
                        for ( deg = 0; deg < mode; deg++){
                                rotate_90_deg();
                        }
                        cube_show_loop(10);
                } else {
                        /* center wave */
                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][3] = B8(00011000);
                                cube[layer][4] = B8(00011000);
                        }
                        cube_show_loop(10);
                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][2] = B8(00011000);
                                cube[layer][3] = B8(00100100);
                                cube[layer][4] = B8(00100100);
                                cube[layer][5] = B8(00011000);
                        }
                        cube_show_loop(10);
                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][1] = B8(00011000);
                                cube[layer][2] = B8(00100100);
                                cube[layer][3] = B8(01000010);
                                cube[layer][4] = B8(01000010);
                                cube[layer][5] = B8(00100100);
                                cube[layer][6] = B8(00011000);
                        }
                        cube_show_loop(10);
                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(00011000);
                                cube[layer][1] = B8(01100110);
                                cube[layer][2] = B8(01000010);
                                cube[layer][3] = B8(10000001);
                                cube[layer][4] = B8(10000001);
                                cube[layer][5] = B8(01000010);
                                cube[layer][6] = B8(01100110);
                                cube[layer][7] = B8(00011000);
                        }
                        cube_show_loop(10);
                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(01000010);
                                cube[layer][1] = B8(10000001);
                                cube[layer][6] = B8(10000001);
                                cube[layer][7] = B8(01000010);
                        }
                        cube_show_loop(10);
                        clear();
                        for ( layer = 0; layer < sonic_layers; layer++){
                                cube[layer][0] = B8(10000001);
                                cube[layer][7] = B8(10000001);
                        }
                        cube_show_loop(10);
                }
        }
//      //
}

/*********************************************************************************/

/*
 * 2x2x2 cubes moving
 * build an 4x4x4 (or 4x4) array to organize the cubes
 * use an own function to map the array to the cube
 * choose xyz by rand, check if there is a cube set
 * if yes, choose a direction by rand
 * check there is neither a bit set in the direction nor
 * the movement would be outside the cube
 * if not, move the pixel, show the cube
 * repeat with check
 * go on with the next pixel
*/

void cube_2_auto( void )
{
        int x,y,z,i,j;
        clear();
        char cube2_arr[4][4];
        for ( i = 0; i < 4; i++){
                for ( j = 0; j < 4; j++){
                        cube2_arr[i][j] = 0;
                }
        }

        cube2_arr[0][0] |= (1 << 0);
        cube2_arr[0][1] |= (1 << 0);
        cube2_arr[0][2] |= (1 << 0);
        cube2_arr[0][3] |= (1 << 0);

        cube2_arr[1][0] |= (1 << 0);
        cube2_arr[1][1] |= (1 << 0);
        cube2_arr[1][2] |= (1 << 0);
        cube2_arr[1][3] |= (1 << 0);

        cube2_arr[0][0] |= (1 << 1);
        cube2_arr[0][1] |= (1 << 1);
        cube2_arr[0][2] |= (1 << 1);
        cube2_arr[0][3] |= (1 << 1);

        cube2_arr[0][0] |= (1 << 2);
        cube2_arr[0][1] |= (1 << 2);
        cube2_arr[0][2] |= (1 << 2);
        cube2_arr[0][3] |= (1 << 2);

        cube2_arr[0][0] |= (1 << 3);
        cube2_arr[0][1] |= (1 << 3);
        cube2_arr[0][2] |= (1 << 3);
        cube2_arr[0][3] |= (1 << 3);

        cube2_arr[1][0] |= (1 << 3);
        cube2_arr[1][1] |= (1 << 3);
        cube2_arr[1][2] |= (1 << 3);
        cube2_arr[1][3] |= (1 << 3);
        cube_2_auto_show(cube2_arr);

        for ( i = 0; i < 2000; i++) {
                /* TODO: make this faster */
                 x = rand()%4;
                 y = rand()%4;
                 z = rand()%4;
                if (cube2_arr[y][x] & (1 << z)) {
                        /*
                         * we have a chosen an existing pixel
                         * now chose a direction and move it until
                         * it hits something
                         */
                        /* stay in case until the
                         * transform functions returns != 0
                         */
                        switch (rand()%6)
                        {
                                case 0:
                                        /* this checks avoid the pixel gets moved outside
                                         * the cube as well as decrementing int = 0
                                         */
                                        while(y < 3) {
                                                if (cube2_move_y_fwd(cube2_arr, y, x, z) == 0) {
                                                        cube_2_auto_show(cube2_arr);
                                                        y++;
                                                } else { break; }
                                        }
                                        break;
                                case 1:
                                        while(y > 0) {
                                                if (cube2_move_y_rev(cube2_arr, y, x, z) == 0) {
                                                        cube_2_auto_show(cube2_arr);
                                                        y--;
                                                } else { break; }
                                        }
                                        break;
                                case 2:
                                        while(x < 3) {
                                                if (cube2_move_x_fwd(cube2_arr, y, x, z) == 0) {
                                                        cube_2_auto_show(cube2_arr);
                                                        x++;
                                                } else { break; }
                                        }
                                        break;
                                case 3:
                                        while(x > 0) {
                                                if (cube2_move_x_rev(cube2_arr, y, x, z) == 0) {
                                                        cube_2_auto_show(cube2_arr);
                                                        x--;
                                                } else { break; }
                                        }
                                        break;
                                case 4:
                                        while(z < 3) {
                                                if (cube2_move_z_fwd(cube2_arr, y, x, z) == 0) {
                                                        cube_2_auto_show(cube2_arr);
                                                        z++;
                                                } else { break; }
                                        }
                                        break;
                                case 5:
                                        while(z > 0) {
                                                if (cube2_move_z_rev(cube2_arr, y, x, z) == 0) {
                                                        cube_2_auto_show(cube2_arr);
                                                        z--;
                                                } else { break; }
                                        }
                                        break;
                                default:
                                        break;
                        }
                }
        }
}

/*
 * no checks for pixel would move outside the cube or inactive pixels
 */

int cube2_move_y_fwd( char cube2[4][4], int y, int x, int z )
{
        /* check if the pixel is already set, if yes, return false */
        if (!(cube2[y+1][x] & (1 << z))){
                cube2[y][x] &= ~(1 << z);
                cube2[y+1][x] |= (1 << z);
                return 0;
        }
        return 1;
}

int cube2_move_y_rev( char cube2[4][4], int y, int x, int z  )
{
        if (!(cube2[y-1][x] & (1 << z))){
                cube2[y][x] &= ~(1 << z);
                cube2[y-1][x] |= (1 << z);
                return 0;
        }
        return 1;
}

int cube2_move_x_fwd( char cube2[4][4], int y, int x, int z  )
{
        if (!(cube2[y][x+1] & (1 << z))){
                cube2[y][x] &= ~(1 << z);
                cube2[y][x+1] |= (1 << z);
                return 0;
        }
        return 1;
}
int cube2_move_x_rev( char cube2[4][4], int y, int x, int z  )
{
        if (!(cube2[y][x-1] & (1 << z))){
                cube2[y][x] &= ~(1 << z);
                cube2[y][x-1] |= (1 << z);
                return 0;
        }
        return 1;
}

int cube2_move_z_fwd( char cube2[4][4], int y, int x, int z  )
{
        if (!(cube2[y][x] & (1 << (z+1)))){
                cube2[y][x] &= ~(1 << z);
                cube2[y][x] |= (1 << (z+1));
                return 0;
        }
        return 1;
}

int cube2_move_z_rev( char cube2[4][4], int y, int x, int z  )
{
        if (!(cube2[y][x] & (1 << (z-1)))){
                cube2[y][x] &= ~(1 << z);
                cube2[y][x] |= (1 << (z-1));
                return 0;
        }
        return 1;
}

void cube_2_auto_show( char cube2[4][4] )
{
        int layer, x,z;
        for ( layer = 0; layer < 4; layer++){
        /* avoid flickering, clear 2 layers only */
                //cube_clear_layer(layer*2+1);
                //cube_clear_layer(layer*2);
                clear();
                for ( x = 0; x < 4; x++){
                        for ( z = 0; z < 4; z++){
                                if (cube2[layer][x] & ( 1 << z)) {
                                        cube[layer*2][x*2] |= (1 << (z*2));
                                        cube[layer*2][x*2] |= (1 << (z*2+1));
                                        cube[layer*2][x*2+1] |= (1 << (z*2));
                                        cube[layer*2][x*2+1] |= (1 << (z*2+1));
                                        cube[layer*2+1][x*2] |= (1 << (z*2));
                                        cube[layer*2+1][x*2] |= (1 << (z*2+1));
                                        cube[layer*2+1][x*2+1] |= (1 << (z*2));
                                        cube[layer*2+1][x*2+1] |= (1 << (z*2+1));
                                }
                        }
                }
        }
        cube_show_loop(10);

}

void cube_outline( void )
{
        int i;
        clear();
        cube_show_loop(6);
        for ( i = 0; i < 8; i++) {
                cube[0][0] |= (1 << i);
                cube[i][0] |= 1;
                cube[0][i] |= 1;
                cube_show_loop(OUTLINE);
        }
        for ( i = 1; i < 8; i++) {
                cube[7][0] |= (1 << i);
                cube[7][i] |= 1;
                cube[i][0] |= 128;
                cube[0][i] |= 128;
                cube[0][7] |= (1 << i);
                cube[i][7] |= 1;
                cube_show_loop(OUTLINE);
        }
        for ( i = 1; i < 8; i++) {
                cube[7][i] |= 128;
                cube[7][7] |= (1 << i);
                cube[i][7] |= 128;
                cube_show_loop(OUTLINE);
        }
        cube_show_loop(20);
        /* shrink */
        clear();
        cube[1][1] = B8(01111110);
        cube[1][6] = B8(01111110);
        cube[6][1] = B8(01111110);
        cube[6][6] = B8(01111110);
        for ( i=2; i< 6; i++) {
                cube[1][i] = B8(01000010);
                cube[6][i] = B8(01000010);
                cube[i][1] = B8(01000010);
                cube[i][6] = B8(01000010);
        }
        cube_show_loop(30);
        rotate_90_auto( 8 );

}
/*********************************************************************************/
/*
 * need special functions, otherwise the bullets would have to be stored
 * in an extra array (-> redraw cube every time)
 */
void invaders_move_right( int layer, int *position )
{
        int check = B8(11000000);
        int i;
        for (i = 0; i < 3; i++){
                /* alway check for 2 bits to make sure its no bullet */
                if ( cube[layer][(*position)] & check ){
                        cube[layer][(*position)] &= ~check;
                        cube[layer-1][(*position)] &= ~check;
                        cube[layer][(*position)+2] |= check;
                        cube[layer-1][(*position)+2] |= check;
                }
                if ( cube[layer][(*position)+3] & check ){
                        cube[layer][(*position)+3] &= ~check;
                        cube[layer-1][(*position)+3] &= ~check;
                        cube[layer][(*position)+5] |= check;
                        cube[layer-1][(*position)+5] |= check;
                }
                check = (check >> 3);
        }
        (*position)++;
}

void invaders_move_left( int layer, int *position )
{
        int check = B8(11000000);
        int i;
        for ( i = 0; i < 3; i++){
                if ( cube[layer][(*position)+1] & check ){
                        cube[layer][(*position)+1] &= ~check;
                        cube[layer-1][(*position)+1] &= ~check;
                        cube[layer][(*position)-1] |= check;
                        cube[layer-1][(*position)-1] |= check;
                }
                if ( cube[layer][(*position)+4] & check ){
                        cube[layer][(*position)+4] &= ~check;
                        cube[layer-1][(*position)+4] &= ~check;
                        cube[layer][(*position)+2] |= check;
                        cube[layer-1][(*position)+2] |= check;
                }
                check = (check >> 3);
        }
        (*position)--;
}

void invaders_move_down( int *layer, int position )
{
        int check = B8(11000000);
        int i;
        for ( i = 0; i < 3; i++){
                if ( cube[(*layer)][position] & check ){
                        cube[(*layer) ][position] &= ~check;
                        cube[(*layer)][position+1] &= ~check;
                        cube[(*layer-2)][position] |= check;
                        cube[(*layer-2)][position+1] |= check;
                }
                if ( cube[(*layer)][position+3] & check ){
                        cube[(*layer)][position+3] &= ~check;
                        cube[(*layer)][position+4] &= ~check;
                        cube[(*layer-2)][position+3] |= check;
                        cube[(*layer-2)][position+4] |= check;
                }
                check = (check >> 3);
        }
        (*layer)--;
}



static void def_fire( int *layer, int *position, int defender_position )
{
        (*position) = defender_position;
        (*layer) = 2;
        cube[(*layer)][(((*position) & 0xF0) >> 4)] |= (1 << ((*position) & 0x0F));
        cube_show_loop(10); /*otherwise first pixel could not be seen */
}

/* usual delay combined with moving the bullet one up */
static void invader_show_loop(int *layer, int *position, int *m_layer, int *m_pos )
{
        static int prescaler = 1;
        int current_layer;
        if ( (*layer) < 7){
                (*layer)++;
                /* check if monster is hit */
                if (cube[(*layer)][(((*position) & 0xF0) >> 4)] & ( 1 << ((*position) & 0x0F)) ) {
                /* flash all pixels around the bullet */
                        current_layer = (*layer)-1;
                        while ( (current_layer <= ((*layer)+1)) && (current_layer < 8)){
                                cube[current_layer][(((*position) & 0xF0) >> 4)+1] |= (7 << (((*position) & 0x0F)-1));
                                cube[current_layer][(((*position) & 0xF0) >> 4)] |= (7 << (((*position) & 0x0F)-1));
                                cube[current_layer][(((*position) & 0xF0) >> 4)-1] |= (7 << (((*position) & 0x0F)-1));
                                current_layer++;
                        }
                        cube_show_loop(14);

                        current_layer = (*layer)-1;
                        while ( (current_layer <= ((*layer)+1)) && (current_layer < 8)){
                                cube[current_layer][(((*position) & 0xF0) >> 4)+1] &= ~(7 << (((*position) & 0x0F)-1));
                                cube[current_layer][(((*position) & 0xF0) >> 4)] &= ~(7 << (((*position) & 0x0F)-1));
                                cube[current_layer][(((*position) & 0xF0) >> 4)-1] &= ~(7 << (((*position) & 0x0F)-1));
                                current_layer++;
                        }
                } else {
                        /* no monster, move up, layer already incremented */
                        cube[(*layer)-1][(((*position) & 0xF0) >> 4)] &= ~(1 << ((*position) & 0x0F));
                        /* always inside the cube, checked by layer < 7*/
                        cube[(*layer)][(((*position) & 0xF0) >> 4)] |= (1 << ((*position) & 0x0F));
                        cube_show_loop(14);
                }
        } else {
                /* delete shot, increment layer to avoid counting up to inf */
                if ( (*layer) < 8) {
                        cube[(*layer)++][(((*position) & 0xF0) >> 4)] &= ~(1 << ((*position) & 0x0F));
                }
                cube_show_loop(14);
        }

        static int direction = 0;
        if ((prescaler % 6) == 0){
                if (((*m_pos) < 3) && (direction == 0)) {
                        MONSTER_RIGHT;
                } else if (((*m_pos) >= 1) && (direction == 1)){
                        MONSTER_LEFT;
                }

                if ((*m_pos) == 3) {
                        direction = 1;
                } else if ((*m_pos) == 0) {
                        direction = 0;
                }
        }
        if ((prescaler % 128) == 0){
                if ((*m_layer) > 2)
                        MONSTER_DOWN;
        }
        if (prescaler < 255)
                prescaler++;
        else
                prescaler = 0;
}

void cube_invaders( void )
{
        clear();
        int monster_layer = 7; /* vert.  monster layer,  */
        int monster_pos = 1; /* hor. monster layer position */
        int defender_pos = 0x43; /* high nibble: x, low nibble: y */
        /* limit to only one shot at once, only defender is able to fire */
        int shot_pos = 0; /* save last shot position */
        int shot_layer = 9; /* current shot layer */
        int i;

        cube[0][3] |= B8(00011100);
        cube[0][4] |= B8(00011100);
        cube[0][5] |= B8(00011100);
        cube[1][4] |= B8(00001000);

        cube[6][1] |= B8(11011011);
        cube[7][1] |= B8(11011011);
        cube[6][2] |= B8(11011011);
        cube[7][2] |= B8(11011011);

        cube[6][4] |= B8(11011011);
        cube[7][4] |= B8(11011011);
        cube[6][5] |= B8(11011011);
        cube[7][5] |= B8(11011011);

        while ( monster_layer > 2 ) {
                for ( i = 0; i < 20; i++){
                        switch (rand() & 0x03)
                        {
                                case 0:
                                        if((defender_pos & 0xF0) < 0x60) { DEF_RIGHT; }
                                        break;
                                case 1:
                                        if((defender_pos & 0xF0) > 0x10) { DEF_LEFT; }
                                        break;
                                case 2:
                                        if((defender_pos & 0x0F) > 0x01) { DEF_FWD; }
                                        break;
                                case 3:
                                        if((defender_pos & 0x0F) < 0x06) { DEF_BACK; }
                                        break;
                                default:
                                        break;
                        }
                        INV_DELAY;
                        INV_DELAY;
                }
                DEF_FIRE;
        }
        cube_explosion();
        clear();
}

/* automated text display, takes a string and adds
 * some effects. Usable for short strings.
 */
void cube_string( char *string )
{
        while(*string){
                clear();

                cube_char(*string, 16);
                string++;
                rotate_90_deg();
                rotate_90_deg();
                rotate_90_deg();
                move_x_rev(1,0,6,7);
                move_x_rev(1,0,6,7);
                move_x_rev(1,0,6,7);

                cube_show_loop(CUBE_STRING_DELAY);
                move_x_fwd(1,0,6,7);
                cube_show_loop(CUBE_STRING_DELAY);
                move_x_fwd(1,0,6,7);
                cube_show_loop(CUBE_STRING_DELAY);
                move_x_fwd(1,0,6,7);
                cube_show_loop(CUBE_STRING_DELAY);
                rotate_90_auto(1);
                move_z_rev(0,0,7,7);
                cube_show_loop(CUBE_STRING_DELAY);
                move_z_rev(0,0,7,7);
                cube_show_loop(CUBE_STRING_DELAY);
                move_z_rev(0,0,7,7);
                cube_show_loop(CUBE_STRING_DELAY);
                move_z_rev(0,0,7,7);
                cube_show_loop(CUBE_STRING_DELAY);
                //cube_flash(5);
                cube_explosion();
        }
        cube_explosion();
        cube_explosion();
}

/* back to front moving */
void cube_string_to_front( char *string )
{
	int i;

        while(*string) {
        	cube_char_b2f_init(*string);
        	for(i=2;i<=8;i+=2){
        		clear();
				cube_char_b2f(i);
				cube_show_loop(i+6);
        	}
        	string++;
        }

}

/* 2 fixed chars rotating */
void cube_fixed_string( void )
{
        clear();
        cube_char('3', 1);
        rotate_90_deg();
        cube_char('D', 1);
        rotate_90_deg();
        rotate_90_auto(8);
}


void cube_waves( void )
{
        int i, times = 12;
        clear();
        for ( i = 0; i < times; i++){
                move_x_rev(0,0,7,7);
                cube[3][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[2][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[1][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[0][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[0][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[1][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[2][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[3][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[4][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[5][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[6][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[7][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[7][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[6][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[5][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
                move_x_rev(0,0,7,7);
                cube[4][7] |= WAVES_DEPTH;
                cube_show_loop(WAVES_DELAY);
        }
}

/*******************************************************************************************/
#define WALKING_DELAY 8

/* small guy who walks in through a door a few steps,
 * after that the environment starts moving for a while
 * I figured out it looks better if the guy heads for
 * the front, so every frame is rotated by 270 deg. I
 * was just too lazy to change everything.
 */

void cube_walking_frame_static0( void )
{
        clear();
        cube[0][0] |= B8(10000000);
        cube[0][1] |= B8(10000001);
        cube[0][2] |= B8(00000001);
        cube[0][3] |= B8(10000000);
        cube[0][4] |= B8(10000000);
        cube[0][5] |= B8(10000001);
        cube[0][6] |= B8(00000001);
        cube[0][7] |= B8(10000000);

        cube[1][0] |= B8(10000000);
        cube[2][0] |= B8(10000000);
        cube[3][0] |= B8(10000000);
        cube[4][0] |= B8(10000000);
        cube[5][0] |= B8(10000000);
        cube[6][0] |= B8(10000000);
        cube[7][0] |= B8(11000000);

        cube[1][4] |= B8(10000000);
        cube[2][4] |= B8(10000000);
        cube[3][4] |= B8(10000000);
        cube[4][4] |= B8(10000000);
        cube[5][4] |= B8(10000000);
        cube[6][4] |= B8(10000000);
        cube[7][4] |= B8(11000000);

        cube[1][1] |= B8(00000001);
        cube[1][2] |= B8(00000001);
        cube[1][5] |= B8(00000001);
        cube[1][6] |= B8(00000001);
}

void cube_walking_frame_static1( void )
{
        clear();
        cube[0][0] |= B8(10000000);
        cube[0][1] |= B8(10000000);
        cube[0][2] |= B8(10000001);
        cube[0][3] |= B8(00000001);
        cube[0][4] |= B8(10000000);
        cube[0][5] |= B8(10000000);
        cube[0][6] |= B8(10000001);
        cube[0][7] |= B8(00000001);

        cube[1][1] |= B8(10000000);
        cube[2][1] |= B8(10000000);
        cube[3][1] |= B8(10000000);
        cube[4][1] |= B8(10000000);
        cube[5][1] |= B8(10000000);
        cube[6][1] |= B8(10000000);
        cube[7][1] |= B8(11000000);

        cube[1][5] |= B8(10000000);
        cube[2][5] |= B8(10000000);
        cube[3][5] |= B8(10000000);
        cube[4][5] |= B8(10000000);
        cube[5][5] |= B8(10000000);
        cube[6][5] |= B8(10000000);
        cube[7][5] |= B8(11000000);

        cube[1][2] |= B8(00000001);
        cube[1][3] |= B8(00000001);
        cube[1][6] |= B8(00000001);
        cube[1][7] |= B8(00000001);
}

void cube_walking_frame_static2( void )
{
        clear();
        cube[0][0] |= B8(00000001);
        cube[0][1] |= B8(10000000);
        cube[0][2] |= B8(10000000);
        cube[0][3] |= B8(10000001);
        cube[0][4] |= B8(00000001);
        cube[0][5] |= B8(10000000);
        cube[0][6] |= B8(10000000);
        cube[0][7] |= B8(10000001);

        cube[1][2] |= B8(10000000);
        cube[2][2] |= B8(10000000);
        cube[3][2] |= B8(10000000);
        cube[4][2] |= B8(10000000);
        cube[5][2] |= B8(10000000);
        cube[6][2] |= B8(10000000);
        cube[7][2] |= B8(11000000);

        cube[1][6] |= B8(10000000);
        cube[2][6] |= B8(10000000);
        cube[3][6] |= B8(10000000);
        cube[4][6] |= B8(10000000);
        cube[5][6] |= B8(10000000);
        cube[6][6] |= B8(10000000);
        cube[7][6] |= B8(11000000);

        cube[1][3] |= B8(00000001);
        cube[1][4] |= B8(00000001);
        cube[1][7] |= B8(00000001);
        cube[1][0] |= B8(00000001);
}

void cube_walking_frame_static3( void )
{
        clear();
        cube[0][0] |= B8(10000001);
        cube[0][1] |= B8(00000001);
        cube[0][2] |= B8(10000000);
        cube[0][3] |= B8(10000000);
        cube[0][4] |= B8(10000001);
        cube[0][5] |= B8(00000001);
        cube[0][6] |= B8(10000000);
        cube[0][7] |= B8(10000000);

        cube[1][3] |= B8(10000000);
        cube[2][3] |= B8(10000000);
        cube[3][3] |= B8(10000000);
        cube[4][3] |= B8(10000000);
        cube[5][3] |= B8(10000000);
        cube[6][3] |= B8(10000000);
        cube[7][3] |= B8(11000000);

        cube[1][7] |= B8(10000000);
        cube[2][7] |= B8(10000000);
        cube[3][7] |= B8(10000000);
        cube[4][7] |= B8(10000000);
        cube[5][7] |= B8(10000000);
        cube[6][7] |= B8(10000000);
        cube[7][7] |= B8(11000000);

        cube[1][4] |= B8(00000001);
        cube[1][5] |= B8(00000001);
        cube[1][0] |= B8(00000001);
        cube[1][1] |= B8(00000001);
}

void cube_walking_frame_door0_open( void )
{
        cube_walking_frame_static0();
        cube[0][7] |= B8(11000011);
        cube[1][7] |= B8(11000011);
        cube[2][7] |= B8(11000011);
        cube[3][7] |= B8(11000011);
        cube[4][7] |= B8(11000011);
        cube[5][7] |= B8(11000011);
        cube[6][7] |= B8(11000011);
        cube[7][7] |= B8(11000011);

        cube[0][6] |= B8(01000000);
        cube[1][6] |= B8(01000000);
        cube[2][6] |= B8(01000000);
        cube[3][6] |= B8(01000000);
        cube[4][6] |= B8(01000000);
        cube[5][6] |= B8(01000000);
        cube[6][6] |= B8(01000000);
        cube[7][6] |= B8(01000000);

        cube[0][5] |= B8(01000000);
        cube[1][5] |= B8(01000000);
        cube[2][5] |= B8(01000000);
        cube[3][5] |= B8(01000000);
        cube[4][5] |= B8(01000000);
        cube[5][5] |= B8(01000000);
        cube[6][5] |= B8(01000000);
        cube[7][5] |= B8(01000000);

        cube[0][4] |= B8(01000000);
        cube[1][4] |= B8(01000000);
        cube[2][4] |= B8(01000000);
        cube[3][4] |= B8(01000000);
        cube[4][4] |= B8(01000000);
        cube[5][4] |= B8(01000000);
        cube[6][4] |= B8(01000000);
        cube[7][4] |= B8(01000000);

        cube[0][3] |= B8(01000000);
        cube[1][3] |= B8(01000000);
        cube[2][3] |= B8(01000000);
        cube[3][3] |= B8(01000000);
        cube[4][3] |= B8(01000000);
        cube[5][3] |= B8(01000000);
        cube[6][3] |= B8(01000000);
        cube[7][3] |= B8(01000000);
}

// do not clear cube, just add three door frames
void cube_walking_frame_door0( void )
{
        int layer;
        cube_walking_frame_static0();

        cube[0][7] |= B8(11111111);
        cube[1][7] |= B8(11111111);
        cube[2][7] |= B8(11111111);
        cube[3][7] |= B8(11111111);
        cube[4][7] |= B8(11111111);
        cube[5][7] |= B8(11111111);
        cube[6][7] |= B8(11111111);
        cube[7][7] |= B8(11111111);

        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY*10);

        cube_walking_frame_static0();
        cube[0][7] |= B8(11000011);
        cube[1][7] |= B8(11000011);
        cube[2][7] |= B8(11000011);
        cube[3][7] |= B8(11000011);
        cube[4][7] |= B8(11000011);
        cube[5][7] |= B8(11000011);
        cube[6][7] |= B8(11000011);
        cube[7][7] |= B8(11000011);

        cube[0][6] |= B8(00100000);
        cube[1][6] |= B8(00100000);
        cube[2][6] |= B8(00100000);
        cube[3][6] |= B8(00100000);
        cube[4][6] |= B8(00100000);
        cube[5][6] |= B8(00100000);
        cube[6][6] |= B8(00100000);
        cube[7][6] |= B8(00100000);

        cube[0][5] |= B8(00010000);
        cube[1][5] |= B8(00010000);
        cube[2][5] |= B8(00010000);
        cube[3][5] |= B8(00010000);
        cube[4][5] |= B8(00010000);
        cube[5][5] |= B8(00010000);
        cube[6][5] |= B8(00010000);
        cube[7][5] |= B8(00010000);

        cube[0][4] |= B8(00001000);
        cube[1][4] |= B8(00001000);
        cube[2][4] |= B8(00001000);
        cube[3][4] |= B8(00001000);
        cube[4][4] |= B8(00001000);
        cube[5][4] |= B8(00001000);
        cube[6][4] |= B8(00001000);
        cube[7][4] |= B8(00001000);
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY*2);

        /* this part is needed more than once */
        cube_walking_frame_door0_open();
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY*2);

/* this is where the guy walks in */
        cube_walking_frame_door0_open();
        cube[0][6] |= B8(00010000);
        cube[1][7] |= B8(00010000);
        cube[3][7] |= B8(00000100);
        cube[6][7] |= B8(00011000);

        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);
        cube_walking_frame_door0_open();
        cube[0][7] |= B8(00011000);

        cube[1][7] |= B8(00011000);
        cube[2][7] |= B8(00111100);
        cube[3][7] |= B8(00111100);
        cube[4][7] |= B8(00111100);

        cube[5][7] |= B8(00011000);

        cube[6][7] |= B8(00011000);
        cube[6][7] |= B8(00011000);
        cube[6][7] |= B8(00011000);

        cube[7][7] |= B8(00011000);

        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);



        cube_walking_frame_door0_open();

        cube[0][4] |= B8(00001000);

        cube[1][5] |= B8(00001000);
        cube[1][7] |= B8(00010000);

        cube[2][4] |= B8(00100000);
        cube[2][6] |= B8(00011000);
/*
 * uncomment this for a "spraining" arm
 *      cube[3][2] = B8(00100000);
 */
        cube[3][5] |= B8(00100000);
        cube[3][6] |= B8(00011000);
        cube[3][7] |= B8(00000100);

        cube[4][6] |= B8(00111100);

        cube[5][6] |= B8(00011000);

        cube[6][5] |= B8(00011000);
        cube[6][6] |= B8(00011000);
        cube[6][7] |= B8(00011000);

        cube[7][6] |= B8(00011000);
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);

        cube_walking_frame_door0_open();
        cube[0][5] |= B8(00011000);


        cube[1][5] |= B8(00011000);
        cube[2][5] |= B8(00111100);
        cube[3][5] |= B8(00111100);
        cube[4][5] |= B8(00111100);

        cube[5][5] |= B8(00011000);

        cube[6][4] |= B8(00011000);
        cube[6][5] |= B8(00011000);
        cube[6][6] |= B8(00011000);

        cube[7][5] |= B8(00011000);
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);


        cube_walking_frame_door0_open();
        cube_walking_frame0();
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
/*
 * at this point the environment starts moving instead
 * of the guy himself
 * we use a small fade in where the door frames are added
 */
        cube_walking_frame_static1();
        cube_walking_frame1();
        for (layer = 0; layer < 8; layer++ ){
                cube[layer][4] |= B8(01000000);
                cube[layer][5] |= B8(01000000);
                cube[layer][6] |= B8(01000000);
                cube[layer][7] |= B8(01000000);
        }
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);

        cube_walking_frame_static2();
        cube_walking_frame2();
        for (layer = 0; layer < 8; layer++ ){
                cube[layer][5] |= B8(01000000);
                cube[layer][6] |= B8(01000000);
                cube[layer][7] |= B8(01000000);
        }
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);

        cube_walking_frame_static3();
        cube_walking_frame3();
        for (layer = 0; layer < 8; layer++ ){
                cube[layer][6] |= B8(01000000);
                cube[layer][7] |= B8(01000000);
        }
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);

        cube_walking_frame_static0();
        cube_walking_frame0();
        for (layer = 0; layer < 8; layer++ ){
                cube[layer][7] |= B8(01000000);
        }
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);

        /* "fade in" finished, we now can go on with the
         * regular loop
         */
}

void cube_walking_walk_out( void )
{
        cube_walking_frame_static1();
        cube_walking_frame2();
        move_x_rev(2,0,5,7);
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);

        cube_walking_frame_static1();
        cube_walking_frame3();
        move_x_rev(2,0,5,7);
        move_x_rev(2,0,5,7);
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);

        cube_walking_frame_static1();

        cube[0][3] |= B8(00001000);

        cube[1][0] |= B8(00010000);
        cube[1][2] |= B8(00001000);

        cube[2][1] |= B8(00011000);
        cube[2][3] |= B8(00100000);

        cube[3][0] |= B8(00000100);
        cube[3][1] |= B8(00011000);
        cube[3][2] |= B8(00100000);

        cube[4][1] |= B8(00111100);

        cube[5][1] |= B8(00011000);

        cube[6][0] |= B8(00011000);
        cube[6][1] |= B8(00011000);
        cube[6][2] |= B8(00011000);

        cube[7][1] |= B8(00011000);
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);


        cube_walking_frame_static1();
        cube[0][0] |= B8(00011000);

        cube[1][0] |= B8(00011000);
        cube[2][0] |= B8(00111100);
        cube[3][0] |= B8(00111100);
        cube[4][0] |= B8(00111100);

        cube[5][0] |= B8(00011000);

        cube[6][0] |= B8(00011000);
        cube[6][0] |= B8(00011000);
        cube[6][0] |= B8(00011000);

        cube[7][0] |= B8(00011000);
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
        cube_show_loop(WALKING_DELAY);
}

void cube_walking_frame0( void )
{
        cube[0][2] |= B8(00010000);
        cube[0][6] |= B8(00001000);

        cube[1][3] |= B8(00010000);
        cube[1][5] |= B8(00001000);

        cube[2][2] |= B8(00000100);
        cube[2][4] |= B8(00011000);
        cube[2][6] |= B8(00100000);

        cube[3][3] |= B8(00000100);
        cube[3][4] |= B8(00011000);
        cube[3][5] |= B8(00100000);

        cube[4][4] |= B8(00111100);

        cube[5][4] |= B8(00011000);

        cube[6][3] |= B8(00011000);
        cube[6][4] |= B8(00011000);
        cube[6][5] |= B8(00011000);

        cube[7][4] |= B8(00011000);
}

void cube_walking_frame1( void )
{
        cube[0][4] |= B8(00011000);


        cube[1][4] |= B8(00011000);
        cube[2][4] |= B8(00111100);
        cube[3][4] |= B8(00111100);
        cube[4][4] |= B8(00111100);

        cube[5][4] |= B8(00011000);

        cube[6][3] |= B8(00011000);
        cube[6][4] |= B8(00011000);
        cube[6][5] |= B8(00011000);

        cube[7][4] |= B8(00011000);
}

void cube_walking_frame2( void )
{
        cube[0][2] |= B8(00001000);
        cube[0][6] |= B8(00010000);

        cube[1][3] |= B8(00001000);
        cube[1][5] |= B8(00010000);

        cube[2][2] |= B8(00100000);
        cube[2][4] |= B8(00011000);
        cube[2][6] |= B8(00000100);

//      cube[3][2] = B8(00100000);
        cube[3][3] |= B8(00100000);
        cube[3][4] |= B8(00011000);
        cube[3][5] |= B8(00000100);

        cube[4][4] |= B8(00111100);

        cube[5][4] |= B8(00011000);

        cube[6][3] |= B8(00011000);
        cube[6][4] |= B8(00011000);
        cube[6][5] |= B8(00011000);

        cube[7][4] |= B8(00011000);
}

void cube_walking_frame3( void )
{
        cube[0][4] |= B8(00011000);


        cube[1][4] |= B8(00011000);
        cube[2][4] |= B8(00111100);
        cube[3][4] |= B8(00111100);
        cube[4][4] |= B8(00111100);

        cube[5][4] |= B8(00011000);

        cube[6][3] |= B8(00011000);
        cube[6][4] |= B8(00011000);
        cube[6][5] |= B8(00011000);

        cube[7][4] |= B8(00011000);
}

void cube_walking( void )
{
        /* disable interrupt and use another loop, flickering otherwise */
        //
        int cycle;
        cube_walking_frame_door0();
                for (cycle = 0; cycle < 13; cycle++){
                        cube_walking_frame_static1();
                        cube_walking_frame1();
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
                        cube_show_loop(WALKING_DELAY);
                        cube_walking_frame_static2();
                        cube_walking_frame2();
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
                        cube_show_loop(WALKING_DELAY);
                        cube_walking_frame_static3();
                        cube_walking_frame3();
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
                        cube_show_loop(WALKING_DELAY);
                        cube_walking_frame_static0();
                        cube_walking_frame0();
        rotate_90_deg();
        rotate_90_deg();
        rotate_90_deg();
                        cube_show_loop(WALKING_DELAY);
                }
        cube_walking_walk_out();
        //
}
#define BLOCK_WIPE_DELAY 5
/* move the actual frame out of the cube */
void cube_block_wipe( void )
{
        int i, layer;
        for ( i = 0; i < 8; i++){
                move_x_fwd(0,0,7,7);
                for( layer = 0; layer < 8; layer++){
                        cube[layer][0] |= 0xFF;
                }
                cube_show_loop(BLOCK_WIPE_DELAY);
        }
        cube_show_loop(BLOCK_WIPE_DELAY);
        for ( i = 8; i != 0; i--){
                for( layer = 0; layer < 8; layer++){
                        cube[layer][i-1] = 0x00;
                }
                cube_show_loop(BLOCK_WIPE_DELAY);
        }

}

/********************************************************************************/

/* moving chars on a belt
 * a cute function to display larger strings.
 * we need to define an own layer for the chars
 * which is then transformed to the cube array
 */

void cube_string_belt( char *string )
{
        /* 2D
         * bits are Y, 0 is bottom, 7 is top
         * 0 is the right end where the chars come in
         * 20 visible lines, 5 are added to the "beginning"
         * outside the cube so the chars can move in
         */
        int i;
        char cube_belt[25];
        for ( i = 0; i < 25; i++) { cube_belt[i] = 0; }


        while(*string){
                set_char_to_belt(*string, cube_belt);
                for ( i = 0; i < 6; i++){
                        show_belt(cube_belt);
                        move_belt_left(cube_belt);
                }
                string++;
        }
        /* move the rest out */
        for ( i = 0; i < 18; i++){
                show_belt(cube_belt);
                move_belt_left(cube_belt);
        }
}

void move_belt_left( char *belt )
{
        int i;
        for ( i = 25; i > 1; i--){
                belt[i-1] = belt[i-2];
        }
        belt[0] = 0;
}
/*
 * set a char to the cube array, then transform this char to
 * the first 5 elements of the belt array
 */
void set_char_to_belt( char character, char *belt )
{
        int layer,i;
        clear();
        cube_char(character, 1);
        for ( layer = 0; layer < 8; layer++) {
                for ( i = 1; i < 6; i++){
                        if (cube[layer][i] & 0x01)
                                belt[5-i] |= (1 << layer);
                }
        }
        clear();
}

/* this function passes the given array to the cube array */
void show_belt( char *belt )
{
        int i,j;
        clear();
        /* right side */
        for ( i = 5; i <= 11; i++){
                for ( j = 0; j < 8; j++){
                        if (belt[i] & (1 << j))
                                cube[j][7] |= (1 << (12-i));
                }
        }
        /* front side */
        for ( i = 12; i <= 17; i++){
                for ( j = 0; j < 8; j++){
                        if (belt[i] & (1 << j))
                                cube[j][18-i] |= (1 << 0);
                }
        }
        /* left side */
        for ( i = 18; i <= 24; i++){
                for ( j = 0; j < 8; j++){
                        if (belt[i] & (1 << j))
                                cube[j][0] |= (1 << (i-17));
                }
        }
        cube_show_loop(SHOW_BELT_DELAY);
}



double
map(double in, double inMin, double inMax, double outMin, double outMax){
	double out;
    out = (in-inMin)/(inMax-inMin)*(outMax-outMin) + outMin;
    return out;
}


void
sine_3d( void ){

	int x,y;
    double z, phase;


    for (phase = PI/4; phase<=(16*PI) + PI/4; phase+=PI/8){

    	clear();

    	for(x = 0; x < NUM_LAYERS; x++){
		   for(y = 0; y < NUM_LAYERS; y++){
				z = sin(phase + sqrt(pow(map(x,0,NUM_LAYERS-1,-PI,PI),2) + pow(map(y,0,NUM_LAYERS-1,-PI,PI),2)));
				z = round(map(z,-1,1,0,NUM_LAYERS-1));
				cube[(int)z][x] = cube[(int)z][x] | 0x01<<y;
		   }
		}

		cube_show_loop(SINE_3D_DELAY);
    }


}

//void
//spiral( void ){
//
//	int x,y;
//    double z, phase;
//
//
//    for (phase = PI/4; phase<=(16*PI) + PI/4; phase+=PI/8){
//
//    	clear();
//
//    	for(x = 0; x < NUM_LAYERS; x++){
//		   for(y = 0; y < NUM_LAYERS; y++){
//				x = sin(z);
//				y = cos(z);
//				cube[(int)z][x] = cube[(int)z][x] | 0x01<<y;
//		   }
//		}
//
//		cube_show_loop(SINE_3D_DELAY);
//    }
//
//
//}





